package com.asen.commons.utils;

import com.asen.commons.core.base.model.BaseEnumEntry;
import com.asen.commons.core.base.model.BaseEnumItem;
import com.asen.commons.core.base.IntegerEnum;
import com.asen.commons.core.base.ObjectEnum;
import com.asen.commons.core.base.StringEnum;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

/**
 * 枚举工具类
 *
 * @author Gary
 * @version 1.0
 * @date 2018-12-16
 */
@Slf4j
public class EnumUtils {

    /**
     * 获取枚举
     *
     * @param enumType
     * @param val
     * @param <E>
     * @return
     */
    public static <E extends ObjectEnum> E valueOf(Class<E> enumType, Object val) {
        if (enumType == null || val == null) {
            return null;
        }

        for (E objectEnum : enumType.getEnumConstants()) {
            if (objectEnum.getValue().equals(val)) {
                return objectEnum;
            }
        }

        return null;
    }

    /**
     * 获取枚举
     *
     * @param enumType
     * @param desc
     * @param <E>
     * @return
     */
    public static <E extends ObjectEnum> E valueOfDesc(Class<E> enumType, String desc) {
        if (enumType == null || desc == null) {
            return null;
        }

        for (E objectEnum : enumType.getEnumConstants()) {
            if (objectEnum.getDesc().equals(desc)) {
                return objectEnum;
            }
        }

        return null;
    }

    /**
     * 获取枚举
     *
     * @param enumType
     * @param name
     * @param <E>
     * @return
     */
    public static <E extends ObjectEnum> E valueOfName(Class<E> enumType, String name) {
        if (enumType == null || name == null) {
            return null;
        }

        for (E objectEnum : enumType.getEnumConstants()) {
            if (((Enum) objectEnum).name().equals(name)) {
                return objectEnum;
            }
        }

        return null;
    }

    /**
     * 获取desc
     *
     * @param enumType
     * @param val
     * @param <E>
     * @return
     */
    public static <E extends ObjectEnum> String getDesc(Class<E> enumType, Object val) {
        if (enumType == null || val == null) {
            return null;
        }
        if (val instanceof ObjectEnum) {
            return ((ObjectEnum) val).getDesc();
        }

        for (E objectEnum : enumType.getEnumConstants()) {
            if (objectEnum.getValue().equals(val)) {
                return objectEnum.getDesc();
            }
        }

        return null;
    }

    public static <E extends ObjectEnum> String[] getDescs(Class<E> enumType) {
        if (enumType == null) {
            return null;
        }
        List<String> descs = new ArrayList<>();
        for (E objectEnum : enumType.getEnumConstants()) {
            descs.add(objectEnum.getDesc());
        }

        return descs.toArray(new String[0]);
    }

    /**
     * 获取desc
     *
     * @param e
     * @param <E>
     * @return
     */
    public static <E extends ObjectEnum> String getDesc(E e) {
        if (e == null) {
            return null;
        }

        return e.getDesc();
    }

    /**
     * 获取Integer值
     *
     * @param enumType
     * @param desc
     * @param <E>
     * @return
     */
    public static <E extends IntegerEnum> Integer getIntValue(Class<E> enumType, String desc) {
        if (enumType == null || desc == null) {
            return null;
        }

        for (E objectEnum : enumType.getEnumConstants()) {
            if (objectEnum.getDesc().equals(desc)) {
                return objectEnum.getValue();
            }
        }

        return null;
    }

    /**
     * 获取String值
     *
     * @param enumType
     * @param desc
     * @param <E>
     * @return
     */
    public static <E extends StringEnum> String getStrValue(Class<E> enumType, String desc) {
        if (enumType == null || desc == null) {
            return null;
        }

        for (E objectEnum : enumType.getEnumConstants()) {
            if (objectEnum.getDesc().equals(desc)) {
                return objectEnum.getValue();
            }
        }

        return null;
    }

    /**
     * 获取枚举项列表
     *
     * @param enumType
     * @param <E>
     * @return
     */
    public static <E extends ObjectEnum> List<E> values(Class<E> enumType) {
        return Arrays.asList(enumType.getEnumConstants());
    }

    /**
     * 枚举与枚举值比较
     *
     * @param enumObj
     * @param value
     * @param <E>
     * @return
     */
    public static <E extends ObjectEnum> boolean equal(E enumObj, Object value) {
        if (enumObj == null || value == null) {
            return false;
        }

        Object v = value;
        if (value instanceof ObjectEnum) {
            v = ((ObjectEnum) value).getValue();
        }

        return enumObj.getValue().equals(v);
    }

    /**
     * 枚举项比较
     *
     * @param enumObj1
     * @param enumObj2
     * @param <E>
     * @return
     */
    public static <E extends ObjectEnum> boolean equal(E enumObj1, E enumObj2) {
        if (enumObj1 == null && enumObj2 == null) {
            return true;
        }

        if (enumObj1 == null && enumObj2 != null
                || enumObj2 != null && enumObj2 == null) {
            return false;
        }

        return enumObj1.equals(enumObj2);
    }

    public static <E extends ObjectEnum> boolean notEqual(E enumObj1, Object value) {
        return !equal(enumObj1, value);
    }

    public static <E extends ObjectEnum> boolean notEqual(E enumObj1, E enumObj2) {
        return !equal(enumObj1, enumObj2);
    }

    public static <E extends ObjectEnum> boolean contains(E[] enumObjs, Object value) {
        if (enumObjs == null || enumObjs.length == 0 || value == null) {
            return false;
        }

        Object v = value;
        if (value instanceof ObjectEnum) {
            v = ((ObjectEnum) value).getValue();
        }

        for (E e : enumObjs) {
            if (e.getValue().equals(v)) {
                return true;
            }
        }

        return false;
    }

    public static <E extends ObjectEnum> boolean contains(Collection<E> enumObjs, Object value) {
        if (enumObjs == null || enumObjs.size() == 0 || value == null) {
            return false;
        }

        Object v = value;
        if (value instanceof ObjectEnum) {
            v = ((ObjectEnum) value).getValue();
        }

        for (E e : enumObjs) {
            if (e.getValue().equals(v)) {
                return true;
            }
        }

        return false;
    }

    public static <E extends ObjectEnum> boolean notContains(E[] enumObjs, Object value) {
        return !contains(enumObjs, value);
    }

    public static <E extends ObjectEnum> boolean notContains(Collection<E> enumObjs, Object value) {
        return !contains(enumObjs, value);
    }

    public static <E extends ObjectEnum> boolean in(Object value, E... enumObjs) {
        return contains(enumObjs, value);
    }

    public static <E extends ObjectEnum> boolean notIn(Object value, E... enumObjs) {
        return !in(value, enumObjs);
    }

    /**
     * 获取枚举名称
     */
//    public static String getEnumName(String className) {
//        if (StringUtils.isBlank(className)) {
//            return null;
//        }
//        RedisCache redisCache = SpringUtil.getBean(RedisCache.class);
//        Object value = redisCache.getHash(CacheTypeEnum.META_DATA, "EnumType#name", className);
//        if (value == null) {
//            // 触发同步枚举名称缓存逻辑
//            String path = "/inner/enumType/getNameByClassName?className=" + className;
//            try {
//                value = RestUtils.get(ServiceNameEnum.PLF_SYS, path, String.class);
//            } catch (Exception e) {
//                log.error("查询枚举名称异常:", e);
//            }
//            // 即时为空也缓存进去,防止雪崩
//            redisCache.putHash(CacheTypeEnum.META_DATA, "EnumType#name", className, StringUtils.sure(value));
//        }
//        return StringUtils.toString(value);
//    }

    public static List<BaseEnumEntry> toEnumList(Class<? extends ObjectEnum> enumClass) {
        if (enumClass == null) {
            return null;
        }
        ObjectEnum[] enums = enumClass.getEnumConstants();
        List<BaseEnumEntry> enumList = new ArrayList<>(enums.length);
        for (ObjectEnum valEnum : enums) {
            BaseEnumEntry entry = new BaseEnumEntry();
            entry.setValue(StringUtils.toString(valEnum.getValue()));
            entry.setDesc(valEnum.getDesc());

            enumList.add(entry);
        }
        return enumList;
    }

    public static List<BaseEnumItem> enumItemList(Class<? extends ObjectEnum> enumClass) {
        if (enumClass == null) {
            return null;
        }
        ObjectEnum[] enums = enumClass.getEnumConstants();
        List<BaseEnumItem> enumList = new ArrayList<>(enums.length);
        for (ObjectEnum valEnum : enums) {
            enumList.add(BaseEnumItem.of(valEnum));
        }
        return enumList;
    }
}
